package com.atguigu.lease.web.app.service.impl;


import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.atguigu.lease.common.constant.RedisConstant;
import com.atguigu.lease.common.exception.LeaseException;
import com.atguigu.lease.common.result.ResultCodeEnum;
import com.atguigu.lease.common.utils.JwtUtil;
import com.atguigu.lease.common.utils.VerifyCodeUtil;
import com.atguigu.lease.model.entity.UserInfo;
import com.atguigu.lease.model.enums.BaseStatus;
import com.atguigu.lease.web.app.service.LoginService;
import com.atguigu.lease.web.app.service.UserInfoService;
import com.atguigu.lease.web.app.vo.user.LoginVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private Client smsClient ;

    @Autowired
    private RedisTemplate<String,String> redisTemplate ;

    @Autowired
    private UserInfoService userInfoService;

    @Override
    public void getSMSCode(String phone) throws Exception {

        //1.手机号为空，抛异常
        if(!StringUtils.hasLength(phone)){
            throw new LeaseException(ResultCodeEnum.APP_LOGIN_PHONE_EMPTY);
        }

        //2.一分钟之内发过短消息的，那么抛异常
        long expire = redisTemplate.getExpire( RedisConstant.APP_LOGIN_PREFIX+phone, TimeUnit.SECONDS);
        if(RedisConstant.APP_LOGIN_CODE_TTL_SEC-expire<RedisConstant.APP_LOGIN_CODE_RESEND_TIME_SEC){
            throw new LeaseException(ResultCodeEnum.APP_SEND_SMS_TOO_OFTEN);
        }

        //3.发短信同时保存到redis
        //3-1.发短信
        SendSmsRequest sendSmsRequest = new SendSmsRequest();
        sendSmsRequest.setSignName("阿里云短信测试");
        sendSmsRequest.setTemplateCode("SMS_154950909");
        sendSmsRequest.setPhoneNumbers(phone);
        String code = VerifyCodeUtil.getVerifyCode(4);
        sendSmsRequest.setTemplateParam("{\"code\":\""+code+"\"}");
        smsClient.sendSms(sendSmsRequest) ;

        //3-2.将验证码保存到redis中，有效时间10分钟
        redisTemplate.opsForValue().set(RedisConstant.APP_LOGIN_PREFIX+phone,code,RedisConstant.APP_LOGIN_CODE_TTL_SEC,TimeUnit.SECONDS);

    }

    @Override
    public String login(LoginVo loginVo) {
        //1.首先校验`phone`和`code`是否为空，若为空，直接响应`手机号码为空`或者`验证码为空`
        if(!StringUtils.hasLength(loginVo.getPhone())){
            throw new LeaseException(ResultCodeEnum.APP_LOGIN_PHONE_EMPTY);
        }else if(!StringUtils.hasLength(loginVo.getCode())){
            throw new LeaseException(ResultCodeEnum.APP_LOGIN_CODE_EMPTY);
        }else{
            String phone = loginVo.getPhone();
            String code = loginVo.getCode();
            //2.根据`phone`从Redis中查询之前保存的验证码，若查询结果为空，则直接响应`验证码已过期`
            String codeFromRedis = redisTemplate.opsForValue().get(RedisConstant.APP_LOGIN_PREFIX + phone);
            if(!StringUtils.hasLength(codeFromRedis)){
                throw new LeaseException(ResultCodeEnum.APP_LOGIN_CODE_EXPIRED);
            }else if(!code.equals(codeFromRedis)){ //3.比较前端发送的验证码和从Redis中查询出的验证码，若不同，则直接响应`验证码错误`
                throw new LeaseException(ResultCodeEnum.APP_LOGIN_CODE_ERROR);
            }else{
                //4.使用`phone`从数据库中查询用户信息，若查询结果为空，则创建新用户，并将用户保存至数据库
                UserInfo userInfoFromDB = userInfoService.getOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getPhone, phone));
                if(userInfoFromDB==null){
                    userInfoFromDB = UserInfo.builder().phone(phone).nickname("用户-"+phone.substring(5)).status(BaseStatus.ENABLE).build();
                    userInfoService.saveOrUpdate(userInfoFromDB);
                }else{
                    //5.判断用户是否被禁用，若被禁，则直接响应`账号被禁用`
                    if(userInfoFromDB.getStatus()==BaseStatus.DISABLE){
                        throw new LeaseException(ResultCodeEnum.APP_ACCOUNT_DISABLED_ERROR);
                    }
                }
                //6.创建JWT并响应给前端
                return JwtUtil.createToken(userInfoFromDB.getId(),userInfoFromDB.getNickname());
            }
        }
    }
}
